#pragma once

#include "Socket.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>

using namespace SocketModule;

class Request
{
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    bool Serialize(std::string &out)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::FastWriter writer;
        out = writer.write(root);
        return true;
    }
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool res = reader.parse(in, root);
        if (res)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        std::cout << res << std::endl;
        return res;
    }
    int X() { return _x; }
    int Y() { return _y; }
    int Oper() { return _oper; }
    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response() {}
    Response(int result, int code) : _result(result), _code(code)
    {
    }
    bool Serialize(std::string &out)
    {
        Json::Value root;
        Json::FastWriter writer;
        root["result"] = _result;
        root["code"] = _code;
        out = writer.write(root);
        return true;
    }
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool res = reader.parse(in, root);
        if (res)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return res;
    }

    void ShowResult()
    {
        std::cout << "计算结果是: " << _result << "[" << _code << "]" << std::endl;
    }
    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }
    ~Response() {}

private:
    int _result;
    int _code;
};

// 协议(基于TCP的)需要解决两个问题：
// 1. request和response必须得有序列化和反序列化功能
// 2. 你必须保证，读取的时候，读到完整的请求(TCP, UDP不用考虑)
class Protocol
{
    using func_t = std::function<Response(Request &)>;
    const std::string sep = "\r\n";

public:
    Protocol()
    {
    }
    Protocol(func_t func) : _func(func)
    {
    }
    std::string Encode(const std::string &jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        std::string package = len + sep + jsonstr + sep;
        return package;
    }
    bool Decode(std::string &buffer, std::string *out)
    {
        auto pos = buffer.find(sep);
        if (pos == std::string::npos)
            return false;
        std::string package_len_str = buffer.substr(0, pos);
        int package_len_int = std::stoi(package_len_str);
        int target_len = package_len_int + sep.size() * 2 + package_len_str.size();
        if (buffer.size() < target_len)
            return false;

        *out = buffer.substr(pos + sep.size(), package_len_int);
        buffer.erase(0, target_len);
        return true;
    }
    void GetRequest(std::shared_ptr<Socket> &psock, InetAddr &addr)
    {
        std::string buffer_queue;
        while (true)
        {
            int n = psock->Recv(&buffer_queue);
            if (n > 0)
            {
                std::string json_package;
                while (Decode(buffer_queue, &json_package))
                {
                    Request req;
                    if (!req.Deserialize(json_package))
                    {
                        continue;
                    }
                    Response resp = _func(req);

                    // 序列化
                    resp.Serialize(json_package);

                    // 添加自定义长度
                    std::string send_str = Encode(json_package); // 携带长度的应答报文了"len\r\n{result:XXX, code:XX}\r\n"

                    // 直接发送
                    psock->Send(send_str);
                }
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client:" << addr.AddrToString() << " Quit!";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client:" << addr.AddrToString() << ", recv error";
                break;
            }
        }
    }
    std::string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);
        std::string json_str;
        req.Serialize(json_str);
        return Encode(json_str);
    }
    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buffer, Response *resp)
    {
        while (true)
        {
            int n = client->Recv(&resp_buffer);
            if (n > 0)
            {
                std::string json_package;
                while (Decode(resp_buffer, &json_package))
                {
                    resp->Deserialize(json_package);
                    return true;
                }
                return true;
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "server quit!";
                return false;
            }
            else
            {
                LOG(LogLevel::WARNING) << "recv error!";
                return false;
            }
        }
    }
    ~Protocol() {}

private:
    func_t _func;
};